//
//  BZThreadGroup.m
//  MZBasic
//
//  Created by Sings on 2023/7/6.
//

#import "BZThreadGroup.h"
#import "BZThreadQueue.h"

@interface BZThreadGroup()

@property (nonatomic, strong) dispatch_queue_t gcdQueue;

@property (nonatomic, strong) dispatch_semaphore_t concurrency;

@property (nonatomic, copy) NSString *strLabel;

@property (nonatomic, assign) NSUInteger iQueue;

@property (nonatomic, strong) dispatch_group_t group;

@property (nonatomic, assign) BOOL stop;

@property (nonatomic, assign) BOOL addStart;

@end

@implementation BZThreadGroup

- (instancetype) initWithiConcurrency:(NSUInteger) iConcurrency {
    self = [super init];
    if (self) {
        NSDateFormatter * formatter = [[NSDateFormatter alloc ] init];
        [formatter setDateFormat:@"YYYY-MM-dd hh:mm:ss:SSS"];
        int x = arc4random() % 100;
        int x1 = arc4random() % 100+100;
        self.strLabel = [NSString stringWithFormat:@"%@%d%d",[formatter stringFromDate:[NSDate date]],x,x1];
        const char *lable = [self.strLabel UTF8String];
        self.gcdQueue = dispatch_queue_create(lable, DISPATCH_QUEUE_SERIAL);
        self.concurrency = dispatch_semaphore_create(iConcurrency);
        self.group = dispatch_group_create();
    }
    return self;
}


- (void) addThreadQueue:(BZThreadQueue *) queue {
    __weak typeof(self) weakSelf = self;
    dispatch_group_enter(self.group);
    dispatch_async(self.gcdQueue, ^{
        dispatch_semaphore_wait(self.concurrency, DISPATCH_TIME_FOREVER);
        weakSelf.iQueue += 1;
        const char *lable_item = [[NSString stringWithFormat:@"%@_iQueue_%lu",weakSelf.strLabel,(unsigned long)weakSelf.iQueue] UTF8String];
        __block BOOL next = YES;
        dispatch_queue_t queue_item = dispatch_queue_create(lable_item, DISPATCH_QUEUE_SERIAL);
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
        dispatch_async(queue_item, ^{
            for (BZThreadQueueTask *queueTask in queue.marTask) {
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                if (next && !weakSelf.stop) {
                    BZThreadQueueTaskFinishedBlock taskFinished = ^(BOOL i_next) {
                        next = i_next;
                        dispatch_semaphore_signal(semaphore);
                    };
                    queueTask.task(taskFinished);
                }else {
                    dispatch_semaphore_signal(semaphore);
                }
            }
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            dispatch_async(dispatch_get_main_queue(), ^{
                dispatch_semaphore_signal(semaphore);
                dispatch_semaphore_signal(weakSelf.concurrency);
                dispatch_group_leave(weakSelf.group);
                if (queue.finished) {
                    queue.finished(next && !weakSelf.stop);
                }
            });
        });
    });
    
    if (self.addStart == NO) {
        self.addStart = YES;
        dispatch_group_notify(self.group, dispatch_get_main_queue(), ^{
            weakSelf.addStart = NO;
            if (weakSelf.finished) {
                weakSelf.finished();
            }
        });
    }
}

- (void) stopAll {
    self.stop = YES;
}

- (void)dealloc {
    NSLog(@"---%@ group dealloc",self.strLabel);
}

@end
